package com.steel.yfmall.cloud.assistant.view.impl;

import com.alibaba.fastjson.JSONObject;
import com.steel.yfmall.cloud.assistant.utils.zg.ZgViewUtil;
import com.steel.yfmall.cloud.assistant.view.EndCodeBeanService;
import com.steel.yfmall.cloud.assistant.zg.ZgSOService;
import com.steel.yfmall.cloud.assistant.dto.para.view.ParaEndCodeBean;
import com.steel.yfmall.cloud.assistant.dto.result.view.ReusltEndCodeBean;
import com.steel.yfmall.cloud.assistant.dto.zg.SynZgResult;
import com.steel.yfmall.cloud.assistant.dto.zg.ZgSOResultBean;
import com.steel.yfmall.cloud.assistant.dto.zg.ZgViewBean;
import com.steel.yfmall.cloud.assistant.po.view.EndCodeBean;
import com.steel.yfmall.cloud.assistant.po.view.EndCodeBeanExample;
import com.steel.yfmall.cloud.assistant.po.view.EndCodeBeanExample.Criteria;
import com.steel.yfmall.cloud.assistant.view.mapper.EndCodeBeanMapper;
import com.steel.yfmall.cloud.components.utils.base.APIMsgBean;
import com.steel.yfmall.cloud.components.utils.base.Pages;
import com.steel.yfmall.cloud.components.utils.base.ResponseCode;
import com.steel.yfmall.cloud.components.utils.utils.MobileBaseBeanUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.util.*;

/**
 * 查询终点代码业务逻辑 接口实现
 *
 * @author jia chang bao
 * @date 2020/11/9 20:48
 */
@Service
@Slf4j
public class EndCodeBeanServiceImpl implements EndCodeBeanService {

    @Resource
    EndCodeBeanMapper endCodeBeanMapper;

    @Resource
    private ZgSOService zgSOService;

    /**
     * 获取终点代码信息总数
     *
     * @param paraEndCodeBean 查询终点代码业务条件
     * @return 终点代码信息总数
     */
    @Override
    public long getEndCodeBeanCount(ParaEndCodeBean paraEndCodeBean) {
        EndCodeBeanExample endCodeBeanExample = new EndCodeBeanExample();
        Criteria criteria = endCodeBeanExample.createCriteria();
        //判断入参对象是否为空
        if (!ObjectUtils.isEmpty(paraEndCodeBean)) {
            getSearchData(criteria, paraEndCodeBean);
        }
        return endCodeBeanMapper.countByExample(endCodeBeanExample);
    }

    /**
     * 分页查询终点代码业务（分页）
     *
     * @param paraEndCodeBean 查询终点代码业务条件
     * @return 分页后的终点代码信息
     */
    @Override
    public Pages<ReusltEndCodeBean> getEndCodeOfPage(ParaEndCodeBean paraEndCodeBean) {
        Pages<ReusltEndCodeBean> returnBean = new Pages<>();
        if (ObjectUtils.isEmpty(paraEndCodeBean)) {
            return null;
        }
        EndCodeBeanExample endCodeBeanExample = new EndCodeBeanExample();
        Criteria criteria = endCodeBeanExample.createCriteria();
        getSearchData(criteria, paraEndCodeBean);

        long result_count_int = endCodeBeanMapper.countByExample(endCodeBeanExample);

        returnBean.paging(paraEndCodeBean.getCurrentPage(), paraEndCodeBean.getPageSize(), result_count_int);
        endCodeBeanExample.limit(returnBean.getStartPosition(), paraEndCodeBean.getPageSize());

        if (StringUtils.isNotBlank(paraEndCodeBean.getOrderByValue())) {
            endCodeBeanExample.setOrderByClause(paraEndCodeBean.getOrderByValue());
        }

        List<EndCodeBean> endCodeBeanList = endCodeBeanMapper.selectByExample(endCodeBeanExample);
        if (!CollectionUtils.isEmpty(endCodeBeanList)) {
            List<ReusltEndCodeBean> reusltEndCodeBeans = new ArrayList<>();
            for (EndCodeBean endCodeBean : endCodeBeanList) {
                ReusltEndCodeBean reusltEndCodeBean = new ReusltEndCodeBean();
                MobileBaseBeanUtils.copyAllFields(endCodeBean, reusltEndCodeBean);
                reusltEndCodeBeans.add(reusltEndCodeBean);
            }
            returnBean.setList(reusltEndCodeBeans);
            return returnBean;
        }
        return null;
    }

    /**
     * 根据条件查询终点代码信息（不分页）
     *
     * @param paraEndCodeBean 查询终点代码业务条件
     * @return 终点代码信息结果（不分页）
     */
    @Override
    public List<ReusltEndCodeBean> getEndCodeOfList(ParaEndCodeBean paraEndCodeBean) {
        //条件为空返回空
        if (ObjectUtils.isEmpty(paraEndCodeBean)) {
            return null;
        }
        EndCodeBeanExample endCodeBeanExample = new EndCodeBeanExample();
        Criteria criteria = endCodeBeanExample.createCriteria();
        getSearchData(criteria, paraEndCodeBean);
        List<EndCodeBean> endCodeBeanList = endCodeBeanMapper.selectByExample(endCodeBeanExample);
        if (!CollectionUtils.isEmpty(endCodeBeanList)) {
            List<ReusltEndCodeBean> list = new ArrayList<>();
            for (EndCodeBean endCodeBean : endCodeBeanList) {
                ReusltEndCodeBean reusltEndCodeBean = new ReusltEndCodeBean();
                MobileBaseBeanUtils.copyAllFields(endCodeBean, reusltEndCodeBean);
                list.add(reusltEndCodeBean);
            }
            return list;
        }

        return null;
    }

    /**
     * 单条新增终点代码信息（单条）
     *
     * @param endCodeBean 终点代码业务条件
     * @return 受影响行数
     */
    @Override
    public int addEndCode(EndCodeBean endCodeBean) {
        return endCodeBeanMapper.insert(endCodeBean);
    }

    /**
     * 批量新增终点代码信息（批量）
     *
     * @param endCodeBeans 终点代码业务条件
     * @return 受影响行数
     */
    @Override
    public int addEndCodeOfList(List<EndCodeBean> endCodeBeans) {
        return endCodeBeanMapper.batchInsertByList(endCodeBeans);
    }

    /**
     * 根据条件修改终点代码信息
     *
     * @param endCodeBean 终点代码业务条件
     * @return 受影响行数
     */
    @Override
    public int updateEndCode(EndCodeBean endCodeBean) {
        if (ObjectUtils.isEmpty(endCodeBean)) {
            return 0;
        }
        EndCodeBeanExample endCodeBeanExample = new EndCodeBeanExample();
        //使用id和area_no联合修改终到地区名称
        endCodeBeanExample.createCriteria().andSiteNoEqualTo(endCodeBean.getSiteNo());
        //设置修改时间
        endCodeBean.setUpdateTime(new Date());
        endCodeBean.setCreateTime(null);
        return endCodeBeanMapper.updateByExampleSelective(endCodeBean, endCodeBeanExample);
    }

    /**
     * 删除终点代码信息（单条）
     *
     * @param paraEndCodeBean 终点代码业务条件
     * @return 受影响行数
     */
    @Override
    public int deleteEndCode(ParaEndCodeBean paraEndCodeBean) {
        if (ObjectUtils.isEmpty(paraEndCodeBean)) {
            return 0;
        }
        EndCodeBeanExample endCodeBeanExample = new EndCodeBeanExample();
        Criteria criteria = endCodeBeanExample.createCriteria();
        getSearchData(criteria, paraEndCodeBean);

        return endCodeBeanMapper.deleteByExample(endCodeBeanExample);
    }

    /**
     * 批量删除终点代码信息（批量）
     *
     * @param paraEndCodeBeans 终点代码业务条件
     * @return 受影响行数
     */
    @Override
    public int deleteEndCodeOfList(List<ParaEndCodeBean> paraEndCodeBeans) {
        if (CollectionUtils.isEmpty(paraEndCodeBeans)) {
            return 0;
        }
        EndCodeBeanExample endCodeBeanExample = new EndCodeBeanExample();
        Criteria criteria = endCodeBeanExample.createCriteria();

        Map<Integer, String> conditionMap = new HashMap<>();
        for (ParaEndCodeBean paraEndCodeBean : paraEndCodeBeans) {
            conditionMap.put(paraEndCodeBean.getId(), paraEndCodeBean.getAreaNo());
        }

        criteria.andIdIn(new ArrayList<>(conditionMap.keySet()));
        return endCodeBeanMapper.deleteByExample(endCodeBeanExample);
    }

    /**
     * 同步中冠终点代码业务信息
     *
     * @param zgViewBean
     * @return 结果
     */
    @Override
    public APIMsgBean synchronizationZgEndCode(ZgViewBean zgViewBean) {
        APIMsgBean serviceDataBean = new APIMsgBean();
        //默认失败
        serviceDataBean.setSoaStateBean(ResponseCode.buildEnumErrorSOAStateBean("数据同步失败"));
        //参数校验
        String msg = checkData(zgViewBean);
        if (!StringUtils.isBlank(msg)) {
            serviceDataBean.setSoaStateBean(ResponseCode.buildEnumErrorSOAStateBean(msg));
            return serviceDataBean;
        }
        SynZgResult synZgResult = new SynZgResult();
        //同步计时开始
        long begintime = System.currentTimeMillis();
        //查询sh02的终到地区去请求
        ZgSOResultBean viewData = zgSOService.getViewData(zgViewBean);
        //同步计时结束
        long endtime = System.currentTimeMillis();
        long costTime = (endtime - begintime);
        //请求中冠成功后
        if ("Y".equals(viewData.getIsSuccess())) {
            List<EndCodeBean> endCodeBeans = null;
            try {
                endCodeBeans = JSONObject.parseArray(viewData.getData(), EndCodeBean.class);
            } catch (Exception e) {
                serviceDataBean.setSoaStateBean(ResponseCode.buildEnumErrorSOAStateBean("终到地区数据同步解析出错"));
                log.error("终到地区数据同步解析出错，错误信息：", e);
            }
            //检查数据库是否有重复,过滤掉重复信息并设置创建、更新、版本信息
            endCodeBeans = checkDataBase(endCodeBeans);
            if (!CollectionUtils.isEmpty(endCodeBeans)) {
                //批量新增
                int i = addEndCodeOfList(endCodeBeans);
                if (i > 0) {
                    //设置同步所用时间
                    synZgResult.setSynTime(String.valueOf(costTime));
                    //设置同步条数
                    synZgResult.setCountNum(i);
                    //设置同步状态
                    synZgResult.setState(true);
                    serviceDataBean.setSoaStateBean(ResponseCode.buildEnumSuccessSOAStateBean("数据同步成功"));
                    serviceDataBean.setData(synZgResult);
                    //日志记录
                    log.info("终到地区数据同步成功，本次同步" + i + "条数据,耗时" + costTime + "毫秒");
                }
            } else {
                log.info("无数据同步");
                serviceDataBean.setSoaStateBean(ResponseCode.buildEnumErrorSOAStateBean("无数据同步"));
            }
        } else {
            serviceDataBean.setSoaStateBean(ResponseCode.buildEnumErrorSOAStateBean(viewData.getMsg()));
        }
        //递归同步
        try {
            //起始页
            int startPage = Integer.parseInt(zgViewBean.getPageNum());
            //判断是否还有数据
            if (startPage < viewData.getZgpageData().getPages()) {
                startPage++;
                zgViewBean.setPageNum(String.valueOf(startPage));
                synchronizationZgEndCode(zgViewBean);
            }
        } catch (Exception e) {
            serviceDataBean.setSoaStateBean(ResponseCode.buildEnumErrorSOAStateBean("终到地区数据递归同步出错"));
            log.error("终到地区数据递归同步出错，错误信息：", e);
        }
        return serviceDataBean;
    }

    /***
     * 检查数据库中数据是否存在，将不存在的数据返回，过滤掉重复的数据
     * @param endCodeBeans 需要检查的数据
     * @return List<PostalCodeBean> 不重复的数据
     */
    private List<EndCodeBean> checkDataBase(List<EndCodeBean> endCodeBeans) {
        if (CollectionUtils.isEmpty(endCodeBeans)) {
            return null;
        }
        EndCodeBeanExample endCodeBeanExample = new EndCodeBeanExample();
        Criteria criteria = endCodeBeanExample.createCriteria();
        //提取终到地区编码和库中数据做比较，如果重复则判定为重复数据。
        Map<String, EndCodeBean> endCodeBeanMap = new HashMap<>();
        for (EndCodeBean endCodeBean : endCodeBeans) {
            endCodeBeanMap.put(endCodeBean.getSiteNo(), endCodeBean);
        }
        //查询数据库是否有重复数据
        Set<String> strings = endCodeBeanMap.keySet();
        ArrayList<String> strings1 = new ArrayList<>(strings);
        criteria.andSiteNoIn(strings1);
        List<EndCodeBean> dbEndCodeBean = endCodeBeanMapper.selectByExample(endCodeBeanExample);
        List<EndCodeBean> oldEndCodeBean = new ArrayList<>();
        //比较是否用重复的数据
        for (EndCodeBean endCodeBean : dbEndCodeBean) {
            String postNo = endCodeBean.getSiteNo();
            if (endCodeBeanMap.containsKey(postNo)) {
                oldEndCodeBean.add(endCodeBeanMap.get(postNo));
                endCodeBeanMap.remove(postNo);
            }
        }
        endCodeBeans = new ArrayList<>(endCodeBeanMap.values());
        for (int i = 0; i < endCodeBeans.size(); i++) {
            endCodeBeans.get(i).setCreateTime(new Date());
            endCodeBeans.get(i).setUpdateTime(new Date());
            endCodeBeans.get(i).setVersionInt(0);
        }
        //当有重复数据是执行同步
        if (!CollectionUtils.isEmpty(oldEndCodeBean)) {
            endCodeBeanMap.clear();
            for (EndCodeBean endCodeBean : oldEndCodeBean) {
                endCodeBeanMap.put(endCodeBean.getSiteNo(), endCodeBean);
            }
            List<EndCodeBean> postalCodeBeans1 = equlstDateChange(endCodeBeanMap);
            if (!CollectionUtils.isEmpty(postalCodeBeans1)) {
                AsynchronousUpDate asynchronousUpDate = new AsynchronousUpDate(postalCodeBeans1);
                new Thread(asynchronousUpDate).start();
            }
        }
        //返回不重复的数据
        return endCodeBeans;
    }

    /**
     * @param oldEndCodeBeanMap 重复的数据
     * @return List<PostalCodeBean> 重复且有差异的信息
     * @Description 校验比较返回重复且有差异的的信息
     * @author jia chang bao
     * @date 2020/11/9 17:17
     */
    private List<EndCodeBean> equlstDateChange(Map<String, EndCodeBean> oldEndCodeBeanMap) {
        //如果对象为空就直接结束
        if (oldEndCodeBeanMap.isEmpty()) {
            return null;
        }
        //条件
        EndCodeBeanExample endCodeBeanExample = new EndCodeBeanExample();
        Criteria criteria = endCodeBeanExample.createCriteria();
        //将邮政编码作为条件
        Set<String> strings = oldEndCodeBeanMap.keySet();
        criteria.andSiteNoIn(new ArrayList<>(strings));
        //查询出重复的数据用于细致比对
        List<EndCodeBean> dbEndCodeBean = endCodeBeanMapper.selectByExample(endCodeBeanExample);
        //用来存储重复且有差异的数据
        List<EndCodeBean> endCodeBeanList = new ArrayList<>();
        //用数据库中的数据和同步过来的数据进行比较
        for (EndCodeBean endCodeBean : dbEndCodeBean) {
            String postNo = endCodeBean.getSiteNo();
            //如果存在相同的邮政编码
            if (oldEndCodeBeanMap.containsKey(postNo)) {
                EndCodeBean endCodeBeanForMap = oldEndCodeBeanMap.get(postNo);
                //当省中文名称 或 市县中文名称 数据存在差异时判定为差异数据
                if (!endCodeBeanForMap.getAreaNo().equals(endCodeBean.getAreaNo())
                        || !endCodeBeanForMap.getSiteChnName().equals(endCodeBean.getSiteChnName())
                        || !endCodeBeanForMap.getDeliveryArea().equals(endCodeBean.getDeliveryArea())
                        || !endCodeBeanForMap.getProvince().equals(endCodeBean.getProvince())
                        || !endCodeBeanForMap.getCity().equals(endCodeBean.getCity())
                        || !endCodeBeanForMap.getConty().equals(endCodeBean.getConty())
                ) {
                    endCodeBeanForMap.setId(endCodeBean.getId());
                    endCodeBeanForMap.setUpdateTime(new Date());
                    endCodeBeanForMap.setVersionInt(endCodeBean.getVersionInt() + 1);
                    endCodeBeanList.add(endCodeBeanForMap);
                }
            }
        }
        return endCodeBeanList;
    }

    /**
     * 线程异步修改重复的数
     */
    private class AsynchronousUpDate implements Runnable {
        List<EndCodeBean> oldEndCodeBean;

        public AsynchronousUpDate(List<EndCodeBean> oldEndCodeBean) {
            this.oldEndCodeBean = oldEndCodeBean;
        }

        @Override
        public void run() {
            //判断是否存在有差异数据，如果有就修改
            try {
                if (!CollectionUtils.isEmpty(oldEndCodeBean)) {
                    //记录总需改数据
                    int i = 0;
                    long begintime = System.currentTimeMillis();
                    for (EndCodeBean endCodeBean : oldEndCodeBean) {
                        i += updateEndCode(endCodeBean);
                    }
                    long endtime = System.currentTimeMillis();
                    long costTime = (endtime - begintime);
                    log.info("异步修改地区同步差异信息成功，本次修改" + i + "条数据，耗时" + costTime + "毫秒");
                }
            } catch (Exception e) {
                log.error("同步后的差异数据修改失败，错误原因：", e);
            }
        }
    }


    /**
     * sql拼接
     *
     * @param criteria        sql拼接
     * @param paraEndCodeBean 参数
     */
    private void getSearchData(Criteria criteria, ParaEndCodeBean paraEndCodeBean) {
        // ID
        if (paraEndCodeBean.getId() != null && paraEndCodeBean.getId() > 0) {
            criteria.andIdEqualTo(paraEndCodeBean.getId());
        }
        // 地点代码
        if (StringUtils.isNotBlank(paraEndCodeBean.getSiteNo())) {
            criteria.andSiteNoEqualTo(paraEndCodeBean.getSiteNo());
        }
        //终到地区
        if (StringUtils.isNotBlank(paraEndCodeBean.getAreaNo())) {
            criteria.andAreaNoEqualTo(paraEndCodeBean.getAreaNo());
        }
        //地点中文名称
        if (StringUtils.isNotBlank(paraEndCodeBean.getSiteChnName())) {
            criteria.andSiteChnNameEqualTo(paraEndCodeBean.getSiteChnName());
        }
        //定价区域
        if (StringUtils.isNotBlank(paraEndCodeBean.getDeliveryArea())) {
            criteria.andDeliveryAreaEqualTo(paraEndCodeBean.getDeliveryArea());
        }
        //省
        if (StringUtils.isNotBlank(paraEndCodeBean.getProvince())) {
            criteria.andProvinceEqualTo(paraEndCodeBean.getProvince());
        }
        //市
        if (StringUtils.isNotBlank(paraEndCodeBean.getCity())) {
            criteria.andCityEqualTo(paraEndCodeBean.getCity());
        }
        //区县
        if (StringUtils.isNotBlank(paraEndCodeBean.getConty())) {
            criteria.andContyEqualTo(paraEndCodeBean.getConty());
        }
        //创建时间
        if (paraEndCodeBean.getCreateTime() != null) {
            criteria.andCreateTimeEqualTo(paraEndCodeBean.getCreateTime());
        }
        //版本号
        if (paraEndCodeBean.getVersionInt() != null && paraEndCodeBean.getVersionInt() > 0) {
            criteria.andVersionIntEqualTo(paraEndCodeBean.getVersionInt());
        }
        //修改时间
        if (paraEndCodeBean.getUpdateTime() != null) {
            criteria.andUpdateTimeEqualTo(paraEndCodeBean.getUpdateTime());
        }
    }

    /**
     * 中冠视图请求的参数校验
     *
     * @param zgViewBean 视图名称
     * @return 校验结果
     */
    private String checkData(ZgViewBean zgViewBean) {
        String msg = "";
        if (!StringUtils.isNotBlank(zgViewBean.getMethod())) {
            msg += "请求方法不能为空";
        }
        if (!StringUtils.isNotBlank(zgViewBean.getViewId())) {
            msg += "请求的视图不能为空";
        }
        if (!StringUtils.isNotBlank(zgViewBean.getPageNum())) {
            msg += "请求的页码不能为空";
        }
        return msg;
    }
}
